package com.yunchao.library.lock

import timber.log.Timber
import java.math.BigInteger


data class LockEPCInfo(
    val id: String, //签封ID
    val version: Int,//版本号
    val voucherType: String,//券别
    val pageNumber: Int,//张数
    val randomNumber: Int,//随机数
    val operationCount: Int,//操作计数器
    val checkCode: String,//校验码
    val stateCode: String, //状态码
    val epc: String, // EPC 信息
    val tId: String? = null, // TID
    val lockErrorCode: String? = null, // TID
    val lockAuthResult: String? = null, // TID
)


fun lockIdToLockEPCInfo(lockId: String, value: String, isClose: Boolean = false): LockEPCInfo {
    val result = getVoucherTypeCode(value).binaryToHex()
    val suffix = if (isClose) "1${result}4E20AE1DBF3341" else "1${result}0000091DC2B340"
    val epcHexStr = "${lockId.toInt().toString(16)}$suffix"
    return getLockEPCInfo(epcHexStr)
}

fun parseLockEPCInfo(
    epcHexStr: String,
    tId: String? = null,
    lockErrorCode: String? = null,
    lockAuthResult: String? = null
) = LockEPCInfo(
    id = Integer.parseInt(epcHexStr.substring(0, 8), 16).toString(),
    version = Integer.parseInt(epcHexStr.substring(8, 9), 16),
    voucherType = epcHexStr.substring(9, 10).hexToBitBinary(4),
    pageNumber = Integer.parseInt(epcHexStr.substring(10, 14), 16),
    randomNumber = Integer.parseInt(epcHexStr.substring(14, 16), 16),
    operationCount = Integer.parseInt(epcHexStr.substring(16, 19), 16),
    checkCode = epcHexStr.substring(19, 22).hexToBitBinary(12),
    stateCode = epcHexStr.substring(22).hexToBitBinary(8),
    epc = epcHexStr,
    tId = tId,
    lockErrorCode = lockErrorCode,
    lockAuthResult = lockAuthResult
)


fun getLockEPCInfo(
    epcHexStr: String,
    tId: String? = null,
    lockErrorCode: String? = null,
    lockAuthResult: String? = null
): LockEPCInfo {
    require(epcHexStr.length == 24) { "EPC长度必须为24个字符" }

    return LockEPCInfo(
        id = parseHexToDecimal(epcHexStr, 0, 8).toString(),    // 32bit
        version = parseHexToDecimal(epcHexStr, 8, 1),         // 4bit
        voucherType = parseHexToBinary(epcHexStr, 9, 1, 4),  // 4bit
        pageNumber = parseHexToDecimal(epcHexStr, 10, 4),     // 16bit
        randomNumber = parseHexToDecimal(epcHexStr, 14, 2),   // 8bit
        operationCount = parseHexToDecimal(epcHexStr, 16, 3), // 12bit
        checkCode = parseHexToBinary(epcHexStr, 19, 3, 12),   // 12bit
        stateCode = parseHexToBinary(epcHexStr, 22, 2, 8),    // 8bit
        epc = epcHexStr,
        tId = tId,
        lockErrorCode = lockErrorCode,
        lockAuthResult = lockAuthResult
    )
}

// 十六进制转十进制工具方法
private fun parseHexToDecimal(hexStr: String, start: Int, length: Int): Int {
    val substring = hexStr.substring(start, start + length)
    return substring.toInt(16)
}

// 十六进制转二进制工具方法
private fun parseHexToBinary(hexStr: String, start: Int, length: Int, bits: Int): String {
    val decimal = parseHexToDecimal(hexStr, start, length)
    return String.format("%${bits}s", decimal.toString(2)).replace(' ', '0')
}


fun LockEPCInfo.getLockStatusStr(): String = when (val status = getLockStatus()) {
    "00" -> "开"
    "01" -> "关"
    "11" -> "未知"
    else -> "非法($status)"
}

fun LockEPCInfo.getLockStatus(): String = stateCode.reversed().substring(0, 2).reversed()


fun LockEPCInfo.getVoucherTypeName(): String =
    when (val type = voucherType) {
        "0001" -> "纸币100元"
        "0010" -> "纸币50元"
        "0011" -> "纸币20元"
        "0100" -> "纸币10元"
        "0101" -> "纸币5元"
        "0110" -> "纸币1元"
        else -> "非法类型($type)"
    }

fun LockEPCInfo.getVoucherTypeId(): String = when (val type = voucherType) {
    "0001" -> "101001"
    "0010" -> "101002"
    "0011" -> "101003"
    "0100" -> "101004"
    "0101" -> "101005"
    "0110" -> "101007"
    else -> "非法类型($type)"
}

fun LockEPCInfo.getVoucherTypeValue(): String = when (voucherType) {
    "0001" -> "100.00"
    "0010" -> "50.00"
    "0011" -> "20.00"
    "0100" -> "10.00"
    "0101" -> "5.00"
    "0110" -> "1.00"
    else -> "0.00"
}

// 根据传入的金额字符串，返回对应的凭证类型代码
fun getVoucherTypeCode(value: String): String {
    // 尝试将金额字符串转换为Double类型，并保留两位小数
    val normalizedAmount = try {
        "%.2f".format(value.toDouble())
    } catch (e: NumberFormatException) {
        // 如果转换失败，则返回"0.00"
        "0.00"
    }
    // 定义金额与凭证类型代码的映射关系
    val mapping = mapOf(
        "100.00" to "0001",
        "50.00" to "0010",
        "20.00" to "0011",
        "10.00" to "0100",
        "5.00" to "0101",
        "1.00" to "0110",
        "0.00" to "0000"
    )
    // 返回对应的凭证类型代码，如果没有找到对应的代码，则返回"0000"
    return mapping[normalizedAmount] ?: "0000"
}


fun LockEPCInfo.checkLock(lockAction: LockAction): LockEPCInfo {
    val stateCode = this.stateCode.reversed()
    Timber.d("checkLock: lockAction = $lockAction   ,  stateCode = $stateCode  , lockEpcInfo = $this")
    //1Bit/0Bit：锁状态标志
    //00：开；01：关；11：未知；10：非法；
    //2Bit为异常标志：0为正常/1为异常
    //3Bit为EPC异常标志：0为正常/1为异常，若为异常则EPC备份区数据用来计算随机因子
    //6Bit为上电标志：0为未上电/1为上电；锁上电后自动设置，正常的操作后，下电时清除
    //7Bit为工作标志：0为工作完成/工作未开始，1为工作中；上电时不能自动清除，必须在一次正常开/关锁操作后清除；
    when (lockAction) {
        // 检查闭锁
        LockAction.CLOSE_LOCK, LockAction.CLOSE_LOCK_LOGISTICS -> {
            check(
                stateCode.substring(3, 4).toInt() == 0
            ) { "闭锁失败,锁号：${id},锁EPC异常" }
            check(
                stateCode.substring(2, 3).toInt() == 0
            ) { "闭锁失败,锁号：${id},锁异常" }
            check(
                stateCode.substring(0, 2).reversed() == "01"
            ) { "闭锁失败,锁号：${id},锁状态： ${getLockStatusStr()}" }
        }

        // 检查开锁
        LockAction.OPEN_LOCK, LockAction.OPEN_LOCK_LOGISTICS -> {
            check(
                stateCode.substring(3, 4).toInt() == 0
            ) { "开锁失败,锁号：${id},锁EPC异常" }
            check(
                stateCode.substring(2, 3).toInt() == 0
            ) { "开锁失败,锁号：${id},锁异常" }
            check(
                stateCode.substring(0, 2).reversed() == "00"
            ) { "开锁失败,锁号：${id},锁状态： ${getLockStatusStr()}" }
        }

        // 检查恢复锁
        LockAction.RECOVERY_LOCK -> {
            check(
                stateCode.substring(3, 4).toInt() != 1
            ) { "锁EPC异常,锁状态： ${getLockStatusStr()}" }
            check(
                stateCode.substring(2, 3).toInt() != 1
            ) { "锁异常,锁号：${id},锁状态： ${getLockStatusStr()}" }
            check(
                stateCode.substring(0, 2).reversed() != "10"
            ) { "锁号：${id}锁状态： ${getLockStatusStr()}" }
        }

        // 其他操作类型不需要检查，直接返回
        else -> return this
    }

    return this
}

fun String.binaryToHex(): String {
    val decimal = Integer.parseInt(this, 2)
    return decimal.toString(16).padStart(1, '0')
}

fun String.hexToBitBinary(len: Int): String {
    return try {
        val binaryString = BigInteger(this, 16).toString(2)
        if (binaryString.length > len) {
            throw IllegalArgumentException("指定的长度 $len 不足以容纳转换后的二进制字符串。")
        }
        binaryString.padStart(len, '0')
    } catch (e: NumberFormatException) {
        throw IllegalArgumentException("输入的字符串不是有效的十六进制字符串。", e)
    }
}

fun String.hexStringToByteArray(): ByteArray {
    val result = ByteArray(length / 2)
    for (i in indices step 2) {
        result[i / 2] = substring(i, i + 2).toInt(16).toByte()
    }
    return result
}


fun ByteArray.byteArrayToHexString(): String {
    return joinToString("") { byte ->
        "%02x".format(byte.toInt() and 0xFF).uppercase()
    }
}

fun byteArrayToString(btAry: ByteArray?, len: Int): String {
    val sb = StringBuilder()
    if (btAry != null) {
        val length = if (len < btAry.size) len else btAry.size
        for (i in 0 until length) {
            sb.append(String.format("%02X ", btAry[i]))
        }
    }
    return sb.toString()
}